/*!
 * \file jxbankc_packet.c
 *
 * \brief JXBANKC数据包处理
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.
 *
 * \version 1.0
 * \author songbb
 * \date 2017/04/19
 *
 */

#include "frzlib.h"
#include "frct_comm.h"

#include "jxbankc_comm.h"
#include "jxbankc_packet.h"
#include "jxbankc_header.h"

int jxbankc_init_packet(L7_jxbankc_packet *p_st_jxbankc_packet)
{
    JXBANKC_PRINT_INFO("init jxbankc_packet...\n");
    if (p_st_jxbankc_packet == NULL)
        return FR_SUCC;

    bytebuff_free(&(p_st_jxbankc_packet->p_st_packet));
    memset(p_st_jxbankc_packet, 0x00, sizeof(L7_jxbankc_packet));
    if ((p_st_jxbankc_packet->p_st_packet = bytebuff_creat()) == NULL)
        return FR_FAIL;
    p_st_jxbankc_packet->ui_len_to_read = 0;
    p_st_jxbankc_packet->fragment_state = APM_JXBANKC_FRAGMENT_INIT;
    p_st_jxbankc_packet->i_is_req = APM_JXBANKC_FLAG_UNSET;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  检查数据是否是分片包
*  ARGS     :  i_is_request                         (是否是请求)
*           :  *p_st_jxbankc_packet                      (JXBANKC数据包)
*           :  i_is_request                         (是否是请求)
*           :  *p_data                              (数据内容)
*           :  ui_len                               (数据长度)
*           :  *p_ui_len_read                       (已读的数据长度)
*           :  *p_ui_len_to_read                    (需读的数据长度)
*  RTN      :  0                                    (是分片包)
*              1                                    (不是分片包)
*              2                                    (出错)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __jxbankc_pkt_is_fragmented(L7_jxbankc_packet *p_st_jxbankc_packet
                                        , char *p_data
                                        , unsigned int ui_len
                                        , unsigned int *p_ui_len_read
                                        , unsigned int *p_ui_len_to_read)
{
    if (jxbankc_header_unpack(p_data, ui_len, &(p_st_jxbankc_packet->st_jxbankc_header)) != FR_SUCC)
        goto error;

    JXBANKC_PRINT_WARN("ui_pkt_len:[%u]\n", p_st_jxbankc_packet->st_jxbankc_header.ui_pkt_len);

    if (ui_len < p_st_jxbankc_packet->st_jxbankc_header.ui_pkt_len)
    {
        *p_ui_len_to_read = p_st_jxbankc_packet->st_jxbankc_header.ui_pkt_len - ui_len;
        *p_ui_len_read = ui_len;
        JXBANKC_PRINT_INFO("__jxbankc_pkt_is_fragmented total_len:[%d] current_len:[%d]\n", p_st_jxbankc_packet->st_jxbankc_header.ui_pkt_len, ui_len);
        goto fragmented;
    }
    else if (ui_len > p_st_jxbankc_packet->st_jxbankc_header.ui_pkt_len)
        goto error;
    else
    {
        *p_ui_len_to_read = 0;
        *p_ui_len_read = p_st_jxbankc_packet->st_jxbankc_header.ui_pkt_len;
        goto not_fragmented;
    }

fragmented:
    return APM_JXBANKC_PACKET_FRAGMENTED;
not_fragmented:
    return APM_JXBANKC_PACKET_UNFRAGMENTED;
error:
    return APM_JXBANKC_PACKET_ERROR;
}

/*******************************************************************************
*  FUNC     :  检查分片包信息
*  ARGS     :  i_is_request                         (是否是请求)
*           :  *p_payload                           (数据内容)
*           :  ui_payload_len                       (数据长度)
*           :  st_timestamp_first                   (分片包时，第一个分片包的时间；不为分片包时与st_timestamp_last相同)
*           :  *p_st_jxbankc_packet                    (JXBANKC数据包)
*  RTN      :  0                                    (是分片包)
*              1                                    (不是分片包)
*              2                                    (出错)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __jxbankc_packet_check_fragment(int i_is_request
                                            , char *p_payload
                                            , unsigned int ui_payload_len
                                            , struct timeval st_timestamp
                                            , L7_jxbankc_packet *p_st_jxbankc_packet)
{
    int i_is_fragmented = 0;
    unsigned int ui_len_read = 0;       // 当前读了多少个字节
    unsigned int ui_len_to_read = 0;    // 还需要读多少个字节

    i_is_fragmented = __jxbankc_pkt_is_fragmented(p_st_jxbankc_packet, p_payload, ui_payload_len, &ui_len_read, &ui_len_to_read);
    JXBANKC_PRINT_CRIT("i_is_fragmented:[%d] ui_len_read:[%d] ui_len_to_read:[%d]\n", i_is_fragmented, ui_len_read, ui_len_to_read);
    if (i_is_fragmented == APM_JXBANKC_PACKET_FRAGMENTED) // 是分片包
    {
        p_st_jxbankc_packet->st_timestamp_first = st_timestamp;
        JXBANKC_PRINT_NOTICE("bytebuff_add first fragmented packet\n");
        if (bytebuff_add(p_st_jxbankc_packet->p_st_packet, p_payload, ui_len_read) != FR_SUCC)
            goto error;
        p_st_jxbankc_packet->ui_len_to_read = ui_len_to_read;
        p_st_jxbankc_packet->fragment_state = i_is_request ? APM_JXBANKC_FRAGMENT_NEED_NEXT_REQ_PACKET : APM_JXBANKC_FRAGMENT_NEED_NEXT_RESP_PACKET;
        goto need_next_packet;
    }
    else if (i_is_fragmented == APM_JXBANKC_PACKET_UNFRAGMENTED) // 不是分片包
    {
        JXBANKC_PRINT_NOTICE("bytebuff_add unfragmented packet\n");
        if (bytebuff_add(p_st_jxbankc_packet->p_st_packet, p_payload, ui_len_read) != FR_SUCC)
            goto error;
        p_st_jxbankc_packet->st_timestamp_first = st_timestamp;
        p_st_jxbankc_packet->st_timestamp_last = st_timestamp;
        p_st_jxbankc_packet->ui_len_to_read = 0;
        p_st_jxbankc_packet->fragment_state = APM_JXBANKC_FRAGMENT_INIT;
    }
    else
        goto error;

    return APM_JXBANKC_CHECK_FRAGMENT_SUCCESS;
need_next_packet:
    JXBANKC_PRINT_WARN("NEED NEXT PACKET!\n");
    return APM_JXBANKC_CHECK_FRAGMENT_NEED_NEXT_PACKET;
error:
    bytebuff_free(&(p_st_jxbankc_packet->p_st_packet));
    return APM_JXBANKC_CHECK_FRAGMENT_ERROR;
}

int jxbankc_packet_unfragment(L7session_jxbankc *p_st_sess
                            , Apm_packet *p_st_packet
                            , L7_jxbankc_packet *p_st_jxbankc_packet)
{
    char *p_payload = NULL;
    unsigned int ui_payload_len = 0;
    int i_fun_ret;

    if (p_st_packet->i_direction == FR_DIRECT_UNKNOWN)
        goto error;

    p_payload = p_st_packet->p_payload;
    ui_payload_len = p_st_packet->ui_payload_len;

    if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV) // 请求包
    {
        if (p_st_jxbankc_packet->fragment_state == APM_JXBANKC_FRAGMENT_NEED_NEXT_RESP_PACKET)
        {
            JXBANKC_PRINT_EMERG("detect unfinshed response fragmented packet\n");
            JXBANKC_PRINT_PACKET("unfinshed error packet", p_st_jxbankc_packet);
            if (jxbankc_init_packet(p_st_jxbankc_packet) != FR_SUCC)
                goto error;
        }
        if (p_st_jxbankc_packet->fragment_state == APM_JXBANKC_FRAGMENT_NEED_NEXT_REQ_PACKET)
        {
            if (p_st_jxbankc_packet->ui_len_to_read > 0)
            {
                if (p_st_packet->ui_payload_len < p_st_jxbankc_packet->ui_len_to_read)
                {
                    JXBANKC_PRINT_NOTICE("bytebuff_add 4\n");
                    if (bytebuff_add(p_st_jxbankc_packet->p_st_packet
                            , p_st_packet->p_payload
                            , p_st_packet->ui_payload_len) != FR_SUCC)
                        goto error;
                    p_st_jxbankc_packet->ui_len_to_read -= p_st_packet->ui_payload_len;
                    p_st_jxbankc_packet->st_timestamp_last = p_st_packet->st_timestamp;
                    goto need_next_packet;
                }
                else if (p_st_packet->ui_payload_len == p_st_jxbankc_packet->ui_len_to_read)
                {
                    JXBANKC_PRINT_NOTICE("bytebuff_add 5\n");
                    if (bytebuff_add(p_st_jxbankc_packet->p_st_packet
                            , p_st_packet->p_payload
                            , p_st_packet->ui_payload_len) != FR_SUCC)
                        goto error;
                    p_st_jxbankc_packet->ui_len_to_read = 0;
                    p_st_jxbankc_packet->st_timestamp_last = p_st_packet->st_timestamp;
                    p_st_jxbankc_packet->fragment_state = APM_JXBANKC_FRAGMENT_INIT;
                    goto success;
                }
                else
                {
                    JXBANKC_PRINT_CRIT("ui_payload_len is great than ui_len_to_read\n");
                    goto error;
                }
            }
        }
        else
        {
            if (jxbankc_init_packet(p_st_jxbankc_packet) != FR_SUCC)
                goto error;
        }

        i_fun_ret = __jxbankc_packet_check_fragment(FR_YES, p_payload, ui_payload_len, p_st_packet->st_timestamp, p_st_jxbankc_packet);
        return i_fun_ret;
    }
    else if (p_st_packet->i_direction == FR_DIRECT_SRV2CLIENT) // 响应包
    {
        if (p_st_jxbankc_packet->fragment_state == APM_JXBANKC_FRAGMENT_NEED_NEXT_REQ_PACKET)
        {
            JXBANKC_PRINT_EMERG("detect unfinshed request fragmented packet\n");
            JXBANKC_PRINT_PACKET("unfinshed error packet", p_st_jxbankc_packet);
            if (jxbankc_init_packet(p_st_jxbankc_packet) != FR_SUCC)
                goto error;
        }
        if (p_st_jxbankc_packet->fragment_state == APM_JXBANKC_FRAGMENT_NEED_NEXT_RESP_PACKET)
        {
            if (p_st_jxbankc_packet->ui_len_to_read > 0)
            {
                if (p_st_packet->ui_payload_len < p_st_jxbankc_packet->ui_len_to_read)
                {
                    JXBANKC_PRINT_NOTICE("bytebuff_add 10\n");
                    if (bytebuff_add(p_st_jxbankc_packet->p_st_packet
                            , p_st_packet->p_payload
                            , p_st_packet->ui_payload_len) != FR_SUCC)
                        goto error;
                    p_st_jxbankc_packet->ui_len_to_read -= p_st_packet->ui_payload_len;
                    p_st_jxbankc_packet->st_timestamp_last = p_st_packet->st_timestamp;
                    goto need_next_packet;
                }
                else if (p_st_packet->ui_payload_len == p_st_jxbankc_packet->ui_len_to_read)
                {
                    JXBANKC_PRINT_NOTICE("bytebuff_add 11\n");
                    if (bytebuff_add(p_st_jxbankc_packet->p_st_packet
                            , p_st_packet->p_payload
                            , p_st_packet->ui_payload_len) != FR_SUCC)
                        goto error;
                    p_st_jxbankc_packet->ui_len_to_read = 0;
                    p_st_jxbankc_packet->st_timestamp_last = p_st_packet->st_timestamp;
                    p_st_jxbankc_packet->fragment_state = APM_JXBANKC_FRAGMENT_INIT;
                    goto success;
                }
                else
                {
                    JXBANKC_PRINT_CRIT("ui_payload_len is great than ui_len_to_read\n");
                    goto error;
                }
            }
        }
        else
        {
            if (jxbankc_init_packet(p_st_jxbankc_packet) != FR_SUCC)
                goto error;
        }

        i_fun_ret = __jxbankc_packet_check_fragment(FR_NO, p_payload, ui_payload_len, p_st_packet->st_timestamp, p_st_jxbankc_packet);
        return i_fun_ret;
    }

success:
    return APM_JXBANKC_CHECK_FRAGMENT_SUCCESS;
need_next_packet:
    JXBANKC_PRINT_WARN("NEED NEXT PACKET!\n");
    return APM_JXBANKC_CHECK_FRAGMENT_NEED_NEXT_PACKET;
error:
    return APM_JXBANKC_CHECK_FRAGMENT_ERROR;
}
